﻿using System;

using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using Silvermoon.Shapes;
using Silvermoon.Windows;
using Silvermoon.Controls.Classes;
using System.Drawing;

namespace Silvermoon.Controls
{
    /// <summary>
    /// Hosts <see cref="TabPage"/>s.
    /// </summary>
    public class TabControl : CompositeControlBase, ICompositeControl
    {
        #region fields

        private Pivot tabs;
        private FlipPanel container;
        const int tabHeight = 80;
        private TabPageCollection pages;
        private bool isCyclic = true;


        #endregion
        #region ctors/dtors
        public TabControl()
            : base()
        {
            Initialize();
        }

        protected override void Dispose(bool dispose)
        {
            pages.Clear();
            base.Dispose(dispose);
        }

        #endregion
        #region props

        public Color UnselectedTextColor
        {
            get { return tabs.UnselectedTextColor; }
            set { tabs.UnselectedTextColor = value; }
        }

        /// <summary>
        /// Gets or sets the space between two tabs. this is also the double value of the space between the left border and the first tab.
        /// </summary>
        public int TabSpace
        {
            get { return tabs.TabSpace; }
            set { tabs.TabSpace = value; }
        }

        public TabPage SelectedPage
        {
            get { return tabs.SelectedNode as TabPage; }
            set { tabs.SelectedNode = value; }
        }

        public int SelectedIndex
        {
            get
            {
                TabPage p = SelectedPage;
                return pages.IndexOf(p);
            }
            set
            {
                if (value < 0 || value >= pages.Count) throw new ArgumentOutOfRangeException("value");
                if (SelectedIndex != value)
                {
                    SelectedPage = pages[value];
                }
            }
        }


        /// <summary>
        /// Gets or sets the <see cref="TabPage"/>s.
        /// </summary>
        public IList<TabPage> Pages
        {
            get { return pages; }
        }

        public bool IsCyclic
        {
            get { return isCyclic; }
            set
            {
                if (isCyclic != value)
                {
                    isCyclic = value;
                    OnPagesChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the background for the tabs area.
        /// </summary>
        public Shape TabBackground
        {
            get { return tabs.Background; }
            set { tabs.Background = value; }
        }

        /// <summary>
        /// Gets or sets the chrome for the tabs area.
        /// </summary>
        public Shape TabChrome
        {
            get { return tabs.Chrome; }
            set { tabs.Chrome = value; }
        }

        public int TabHeight
        {
            get { return tabs.Height; }
            set
            {
                if (TabHeight != value)
                {
                    tabs.Height = value;
                    container.Margin = new Margin(0, value, 0, 0);
                }
            }
        }

        #endregion
        #region methods

        public void SetPages(params TabPage[] pages)
        {
            foreach (var page in pages)
            {
                this.pages.Add(page);
            }
        }

        protected virtual void OnPagesChanged()
        {
            tabs.SelectedNode = LinkTabItems();
        }

        private void UnlinkItems(IEnumerable<TabPage> pages)
        {
            tabs.SelectedNode = null;
            if (pages != null)
            {
                foreach (TabPage item in pages)
                {
                    item.tabControl = null;
                    item.Previous = null;
                    item.Next = null;
                    item.Dispose();
                }
            }
        }

        private TabPage LinkTabItems()
        {
            TabPage first = null;
            TabPage last = null;
            if (pages != null)
            {
                foreach (TabPage item in pages)
                {
                    item.tabControl = this;
                    if (last != null) last.Next = item;
                    item.Previous = last;
                    last = item;
                    if (first == null) first = item;

                }
            }

            if (last != first)
            {
                if (isCyclic)
                {
                    last.Next = first;
                    first.Previous = last;
                }
            }
            else
            {
                if (first != null)
                {
                    first.Next = null;
                    first.Previous = null;
                }

            }
            return first;
        }

        private void Initialize()
        {
            pages = new TabPageCollection(this);
            tabs = new Pivot
            {
                Mode = PivotMode.Tabbed,
                Margin = new Margin(0, 0, 0, null),
                Height = tabHeight,
                TileSizeFactor = 2f,
                TabSpace = 24
            };

            tabs.OffsetChanged += new EventHandler(tabs_NodeChanging);
            tabs.NodeChanged += new EventHandler<NodeChangedEventArgs>(OnNodeChanged);

            container = new FlipPanel
            {
                Margin = new Margin(0, tabHeight, 0, 0)
            };
            container.SynchronizeWith(tabs);
            tabs.GetControl += (s, e) => e.Control = (e.Navigation as TabPage).Label;
            container.GetControl += (s, e) => e.Control = (e.Navigation as TabPage).Container;
            VisibleControls.Add(container, tabs);
            Margin = Margin.Zero;
        }

        void tabs_NodeChanging(object sender, EventArgs e)
        {
            OnPageChanging();
        }

        private void OnNodeChanged(object sender, NodeChangedEventArgs e)
        {
            OnPageChanged(sender, e.NewValue as TabPage);
        }

        protected virtual void OnPageChanged(object sender, TabPage page)
        {
            if (PageChanged != null)
            {
                PageChanged(this, EventArgs.Empty);
            }
        }

        protected override void ApplyStyle()
        {
            base.ApplyStyle();
            if (tabs.Background == null) tabs.Background = GetTabBackground();
        }

        /// <summary>
        /// Gets the default background for the tabs area.
        /// </summary>
        /// <returns></returns>
        protected virtual Shape GetTabBackground()
        {
            //return PhoneColors.MediumDark;
            return null;
        }

        internal void UpdateItem(TabPage tabItem)
        {
            tabs.Invalidate(InvalidationFlag.Layout);
            container.Invalidate(InvalidationFlag.Layout);
        }

        public void SetPage(TabPage page, bool animated)
        {
            tabs.SelectNode(page, animated);
        }

        protected virtual void OnPageChanging()
        {
            if (PageChanging != null) PageChanging(this, EventArgs.Empty);
        }

        public void OnTabCollectionChanged()
        {
            OnPagesChanged();
        }

        #endregion
        #region events

        public event EventHandler PageChanging;
        public event EventHandler PageChanged;

        #endregion

    }
}
